{*******************************************************************************
* The contents of this file are used with permission, subject to the Mozilla   *
* Public License Version 1.1 (the "License"); you may not use this file except *
* in compliance with the License. You may obtain a copy of the License at      *
* http://www.mozilla.org/MPL/                                                  *
*                                                                              *
* Software distributed under the License is distributed on an "AS IS" basis,   *
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for *
* the specific language governing rights and limitations under the License.    *
*                                                                              *
* The Original Code is distributed as part of the "mediate" product and is     *
* Copyright (C) @home media limited. All Rights Reserved.                      *
*                                                                              *
* Email: support@athomemedia.co.uk                                             *
* Web:   http://www.athomemedia.co.uk                                          *
*******************************************************************************}

unit CoverSearch;

interface

uses XMLHelper;

type
  TAHMCoverSearch = class
  private
    FURL: String;
    FHTML: String;
    FImageURL: String;
    FSearch: String;
    FHelper: TAHMXMLHelper;
  protected
    function ComposeRequest: Boolean; virtual; abstract;
    function RetrieveResponse: Boolean;
    function ParseResponse: Boolean; virtual; abstract;
  public
    property ImageURL: String read FImageURL;
    function Search(SearchString: String): Boolean;
  end;

  TAHMAmazonCoverSearch = class(TAHMCoverSearch)
  protected
    function ComposeRequest: Boolean; override;
    function ParseResponse: Boolean; override;
  end;

  TAHMCoverSearcher = class
  private
    FImageURL: String;
    FAmazon: TAHMAmazonCoverSearch;
  public
    constructor Create;
    destructor Destroy; override;
    property ImageURL: String read FImageURL;
    function Search(SearchString: String): Boolean;
    function Download(FileName: WideString): Boolean;
  end;

implementation

uses Classes, SysUtils, InternetHelper;

// TAHMCoverSearch

function TAHMCoverSearch.RetrieveResponse: Boolean;
begin
  FHTML := '';

  // Validate request URL
  if FURL <> '' then
    try
      FHTML := InternetHelperInstance.Get(FURL);
    except
      // Ignore exceptions whilst retrieving response
    end;

  // Validate response
  Result := FHTML <> '';
end;

function TAHMCoverSearch.Search(SearchString: string): Boolean;
begin
  FImageURL := '';
  FSearch := SearchString;

  Result := ComposeRequest and RetrieveResponse and ParseResponse;
end;

// TAHMAmazonCoverSearch

function TAHMAmazonCoverSearch.ComposeRequest: Boolean;
const
  AMAZON_SEARCH_URL = 'http://webservices.amazon.com/onca/xml?' +
                      'Service=AWSECommerceService&' +
                      'SubscriptionId=1A7XKHR5BYD0WPJVQEG2&' +
                      'Operation=ItemSearch&' +
                      'SearchIndex=Music&' +
                      'ResponseGroup=Images&' +
                      'Version=2006-06-28&' +
                      'Keywords=%0:s';
begin
  // Build search URL for Amazon REST API
  FURL := Format(AMAZON_SEARCH_URL, [InternetHelperInstance.EncodeParams(FSearch)]);
  Result := True;
end;

function TAHMAmazonCoverSearch.ParseResponse: Boolean;
const
  TAG_RESPONSE = 'ItemSearchResponse';
  TAG_ITEMS = 'Items';
  TAG_ITEM = 'Item';
  TAG_LARGEIMAGE = 'LargeImage';
  TAG_URL = 'URL';
var
  RootNode, ItemsNode, ItemNode, ImageNode, URLNode: TAHMXMLNode;
begin
  // Default result - problem parsing response
  Result := False;

  FHelper := TAHMXMLHelper.Create;
  try
    try
      FHelper.DocumentXML := FHTML;

      // Ignore preamble - we're looking for an ItemSearchResponse node
      if not FHelper.FindRootElement(RootNode, TAG_RESPONSE) then Exit;

      // Look for the Items node
      ItemsNode := nil;
      if FHelper.FindElement(RootNode, ItemsNode, TAG_ITEMS) then
      begin
        // Iterate through all returned Item nodes
        ItemNode := nil;
        while FHelper.FindElement(ItemsNode, ItemNode, TAG_ITEM) do
        begin
          // Look for a LargeImage node
          ImageNode := nil;
          if FHelper.FindElement(ItemNode, ImageNode, TAG_LARGEIMAGE) then
          begin
            // Look for the URL node
            URLNode := nil;
            if FHelper.FindElement(ImageNode, URLNode, TAG_URL) then
            begin
              // This is the URL for the large image
              FImageURL := FHelper.GetValue;
              if FImageURL <> '' then
              begin
                Result := True;
                Exit;
              end;
            end;
          end;
        end;
      end;
    except
      // Ignore XML parsing exceptions
    end;
  finally
    FHelper.Free;
  end;
end;

// TAHMCoverSearcher

constructor TAHMCoverSearcher.Create;
begin
  inherited;

  // Create instances of each supported search type
  FAmazon := TAHMAmazonCoverSearch.Create;
end;

destructor TAHMCoverSearcher.Destroy;
begin
  // Release search instances
  FAmazon.Free;

  inherited;
end;

function TAHMCoverSearcher.Search(SearchString: String): Boolean;
begin
  // Apply search against all supported sources
  if FAmazon.Search(SearchString) then
  begin
    FImageURL := FAmazon.ImageURL;
    Result := True;
  end
  else
  begin
    FImageURL := '';
    Result := False;
  end;
end;

function TAHMCoverSearcher.Download(FileName: WideString): Boolean;
var
  Stream: TMemoryStream;
begin
  // Set default result - failed to download
  Result := False;

  Stream := TMemoryStream.Create;
  try
    try
      if InternetHelperInstance.GetResource(FImageURL, Stream) then
      begin
        Stream.Seek(0, soFromBeginning);
        Stream.SaveToFile(FileName);
        Result := True;
      end;
    except
      // Ignore IO exceptions whilst downloading
    end;
  finally
    Stream.Free;
  end;
end;


end.
